package it.txt.access.capability.spi.resource.http.model;

import it.txt.access.capability.spi.resource.exception.URISyntaxException;
import it.txt.access.capability.spi.resource.model.ICapabilityResourceIDModel;

import java.net.URI;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.validator.routines.IntegerValidator;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.client.utils.URLEncodedUtils;

/**
 *
 * @author seccia
 * @author Salvatore Piccione (TXT e-solutions SpA - salvatore.piccione AT txtgroup.com)
 */
public class HTTPResourceIDModel implements ICapabilityResourceIDModel{    
    private static final int TCP_PORT_NUMBER_MAX;
    private static final int TCP_PORT_NUMBER_MIN;
    private static final String TCP_PORT_RANGE_MESSAGE;
    private static final Set<String> ALLOWED_SCHEMES;
    private static final String SUPPORTED_SCHEMES_MESSAGE;
    
    static {
        final String TCP_PORT_NUMBER_MAX_KEY = "port-number-max";
        final String TCP_PORT_NUMBER_MIN_KEY = "port-number-min";
        final String ALLOWED_SCHEME_LIST_KEY = "supported-schemes";
        final String SUPPORTED_SCHEMES_MESSAGE_KEY = "supported-schemes-message";
        ResourceBundle constraintsBundle = ResourceBundle.getBundle("resource-bundles/constraints");
        TCP_PORT_NUMBER_MAX = Integer.parseInt(constraintsBundle.getString(TCP_PORT_NUMBER_MAX_KEY));
        TCP_PORT_NUMBER_MIN = Integer.parseInt(constraintsBundle.getString(TCP_PORT_NUMBER_MIN_KEY));
        TCP_PORT_RANGE_MESSAGE = MessageFormat.format(constraintsBundle.getString("port-range-message"),
                HTTPResourceIDModel.TCP_PORT_NUMBER_MIN, HTTPResourceIDModel.TCP_PORT_NUMBER_MAX);
        String[] schemesArray = constraintsBundle.getString(ALLOWED_SCHEME_LIST_KEY).split("\\,");
        ALLOWED_SCHEMES = new HashSet<String>();
        for (String scheme : schemesArray)
            ALLOWED_SCHEMES.add(scheme);
        SUPPORTED_SCHEMES_MESSAGE = constraintsBundle.getString(SUPPORTED_SCHEMES_MESSAGE_KEY);
    }
    
    private URIBuilder builder;
    private URI uri;
    
    public HTTPResourceIDModel () {
        builder = new URIBuilder();
    }
    

    public String getFragment() {
        return builder.getFragment();
    }

    public void setFragment(String fragment) {
        if (null != fragment && fragment.isEmpty()) 
            throw new IllegalArgumentException("The fragment cannot be an empty string");
        builder.setFragment(fragment);
    }

    public String getHost() {
        return builder.getHost();
    }

    public void setHost(String host) {
        if (host == null)
            throw new IllegalArgumentException("The host cannot be null");
        if (host.isEmpty()) 
            throw new IllegalArgumentException("The host cannot be an empty string");
        builder.setHost(host);
    }

    public String getPath() {
        return builder.getPath();
    }

    public void setPath(String path) {
        if (null != path && path.isEmpty()) 
            throw new IllegalArgumentException("The path cannot be an empty string");
        if (null != path) {
            if (path.startsWith("/"))
                builder.setPath(path);
            else
                builder.setPath("/" + path);
        }
    }

    public int getPort() {
        return builder.getPort();
    }

    public void setPort(int port) throws ValidationException {
        IntegerValidator validator = new IntegerValidator();
        if (validator.isInRange(port, TCP_PORT_NUMBER_MIN, TCP_PORT_NUMBER_MAX)) {
            builder.setPort(port);
        }
        else
            throw new ValidationException(TCP_PORT_RANGE_MESSAGE);
    }

    public String getQuery() {
        return URLEncodedUtils.format(builder.getQueryParams(),"UTF-8");
    }

    public void setQuery(String query) {
        if (null != query && query.isEmpty()) 
            throw new IllegalArgumentException("The query cannot be an empty string");
        if (null != query)
            builder.setQuery(query);
    }

    public String getScheme() {
        return builder.getScheme();
    }

    public void setScheme(String scheme) throws ValidationException {
        if (null != scheme && scheme.isEmpty()) 
            throw new IllegalArgumentException("The scheme cannot be an empty string");
        if (ALLOWED_SCHEMES.contains(scheme)) {
            builder.setScheme(scheme);
        }
        else
            throw new ValidationException(SUPPORTED_SCHEMES_MESSAGE);
    }
    
    public void setURI(URI uri) {
        if (uri == null)
            throw new IllegalArgumentException("The URI cannot be null");
        this.uri = uri;
    }

    @Override
    public String toString(){
        try {
            return toURI().toString();
        } catch (URISyntaxException ex) {
            Logger.getLogger(HTTPResourceIDModel.class.getName()).log(Level.SEVERE, null, ex);
            return "<BAD URI>";
        }
    }

    public URI toURI() throws URISyntaxException{
        try {
            if (uri != null)
                return uri;
            return builder.build();
        } catch (java.net.URISyntaxException e) {
            throw new URISyntaxException(e.getMessage(),e);
        }
            
    }
}
